#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSpinBox>
#include <QLineEdit>
#include <QTextEdit>
#include <QPushButton>
#include <QLabel>
#include <QGridLayout>
#include <QWidget>
#include <QMessageBox>
#include <QGroupBox>
#include <QScrollArea>
#include <QFrame>
#include <QFont>
#include <QTabWidget>
#include <QSplitter>
#include <QProgressBar>
#include <QTimer>
#include <QIntValidator>
#include <QDoubleValidator>
#include <QWheelEvent>
#include <QRegularExpressionValidator>
#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>
#include <cmath>
#include <regex>

class Fraction {
private:
    long long numerator;
    long long denominator;

    long long gcd(long long a, long long b) const {
        return b == 0 ? a : gcd(b, a % b);
    }

    void simplify() {
        if (denominator == 0) {
            throw std::runtime_error("Denominator cannot be zero");
        }

        if (denominator < 0) {
            numerator = -numerator;
            denominator = -denominator;
        }

        long long common = gcd(std::abs(numerator), std::abs(denominator));
        numerator /= common;
        denominator /= common;
    }

public:
    Fraction(long long num = 0, long long den = 1) : numerator(num), denominator(den) {
        simplify();
    }

    // 从字符串构造分数（支持整数、小数、分数格式）
    Fraction(const std::string& str) {
        std::string s = str;
        // 移除空格
        s.erase(std::remove(s.begin(), s.end(), ' '), s.end());

        // 检查分数格式
        size_t slash_pos = s.find('/');
        if (slash_pos != std::string::npos) {
            // 分数格式: a/b
            std::string num_str = s.substr(0, slash_pos);
            std::string den_str = s.substr(slash_pos + 1);

            // 处理分子中的符号
            bool negative = false;
            if (!num_str.empty() && num_str[0] == '-') {
                negative = true;
                num_str = num_str.substr(1);
            }

            numerator = std::stoll(num_str);
            denominator = std::stoll(den_str);

            if (negative) {
                numerator = -numerator;
            }
        }
        // 检查小数格式
        else if (s.find('.') != std::string::npos) {
            // 小数格式: a.b
            size_t dot_pos = s.find('.');
            std::string int_part = s.substr(0, dot_pos);
            std::string frac_part = s.substr(dot_pos + 1);

            bool negative = false;
            if (!int_part.empty() && int_part[0] == '-') {
                negative = true;
                int_part = int_part.substr(1);
            }

            long long integer = int_part.empty() ? 0 : std::stoll(int_part);
            long long fraction = std::stoll(frac_part);
            long long denom = 1;

            for (size_t i = 0; i < frac_part.length(); i++) {
                denom *= 10;
            }

            numerator = integer * denom + fraction;
            denominator = denom;

            if (negative) {
                numerator = -numerator;
            }
        }
        else {
            // 整数格式
            numerator = std::stoll(s);
            denominator = 1;
        }
        simplify();
    }

    long long getNumerator() const { return numerator; }
    long long getDenominator() const { return denominator; }

    double toDouble() const {
        return static_cast<double>(numerator) / denominator;
    }

    double value() const {
        return static_cast<double>(numerator) / denominator;
    }

    Fraction operator+(const Fraction& other) const {
        long long num = numerator * other.denominator + other.numerator * denominator;
        long long den = denominator * other.denominator;
        return Fraction(num, den);
    }

    Fraction operator-(const Fraction& other) const {
        long long num = numerator * other.denominator - other.numerator * denominator;
        long long den = denominator * other.denominator;
        return Fraction(num, den);
    }

    Fraction operator*(const Fraction& other) const {
        long long num = numerator * other.numerator;
        long long den = denominator * other.denominator;
        return Fraction(num, den);
    }

    Fraction operator/(const Fraction& other) const {
        if (other.numerator == 0) {
            throw std::runtime_error("Division by zero error");
        }
        long long num = numerator * other.denominator;
        long long den = denominator * other.numerator;
        return Fraction(num, den);
    }

    Fraction operator-() const {
        return Fraction(-numerator, denominator);
    }

    bool operator==(const Fraction& other) const {
        return numerator == other.numerator && denominator == other.denominator;
    }

    bool operator!=(const Fraction& other) const {
        return !(*this == other);
    }

    bool operator>(const Fraction& other) const {
        return value() > other.value();
    }

    bool operator<(const Fraction& other) const {
        return value() < other.value();
    }

    bool operator>=(const Fraction& other) const {
        return value() >= other.value();
    }

    bool operator<=(const Fraction& other) const {
        return value() <= other.value();
    }

    Fraction abs() const {
        return Fraction(std::abs(numerator), denominator);
    }

    std::string toString() const {
        if (denominator == 1) {
            return std::to_string(numerator);
        }
        else {
            return std::to_string(numerator) + "/" + std::to_string(denominator);
        }
    }
};

class LinearEquationSolver {
private:
    Fraction determinant(const std::vector<std::vector<Fraction>>& matrix) {
        int n = matrix.size();

        if (n == 1) {
            return matrix[0][0];
        }
        else if (n == 2) {
            return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
        }
        else {
            Fraction det(0);
            for (int i = 0; i < n; i++) {
                std::vector<std::vector<Fraction>> minor(n - 1, std::vector<Fraction>(n - 1));
                for (int j = 1; j < n; j++) {
                    int colIndex = 0;
                    for (int k = 0; k < n; k++) {
                        if (k != i) {
                            minor[j - 1][colIndex++] = matrix[j][k];
                        }
                    }
                }
                Fraction cofactor = determinant(minor);
                if (i % 2 == 1) {
                    cofactor = -cofactor;
                }
                det = det + matrix[0][i] * cofactor;
            }
            return det;
        }
    }

    std::vector<Fraction> solveSystemGaussian(std::vector<std::vector<Fraction>> A,
                                             std::vector<Fraction> b) {
        int n = A.size();

        for (int i = 0; i < n; i++) {
            int maxRow = i;
            for (int k = i + 1; k < n; k++) {
                if (A[k][i].abs().value() > A[maxRow][i].abs().value()) {
                    maxRow = k;
                }
            }

            std::swap(A[i], A[maxRow]);
            std::swap(b[i], b[maxRow]);

            if (A[i][i] == Fraction(0)) {
                throw std::runtime_error("Coefficient matrix is singular, no unique solution");
            }

            for (int k = i + 1; k < n; k++) {
                Fraction factor = A[k][i] / A[i][i];
                for (int j = i; j < n; j++) {
                    A[k][j] = A[k][j] - factor * A[i][j];
                }
                b[k] = b[k] - factor * b[i];
            }
        }

        std::vector<Fraction> x(n);
        for (int i = n - 1; i >= 0; i--) {
            x[i] = b[i];
            for (int j = i + 1; j < n; j++) {
                x[i] = x[i] - A[i][j] * x[j];
            }
            x[i] = x[i] / A[i][i];
        }

        return x;
    }

    std::vector<Fraction> solveSystemCramer(const std::vector<std::vector<Fraction>>& coefficients,
                                           const std::vector<Fraction>& constants) {
        int n = coefficients.size();
        Fraction mainDet = determinant(coefficients);

        if (mainDet == Fraction(0)) {
            throw std::runtime_error("Coefficient matrix determinant is zero, no unique solution");
        }

        std::vector<Fraction> solution(n);

        for (int i = 0; i < n; i++) {
            std::vector<std::vector<Fraction>> replacedMatrix = coefficients;
            for (int j = 0; j < n; j++) {
                replacedMatrix[j][i] = constants[j];
            }
            Fraction replacedDet = determinant(replacedMatrix);
            solution[i] = replacedDet / mainDet;
        }

        return solution;
    }

    std::string getVariableName(int index) {
        if (index < 26) {
            return std::string(1, 'A' + index);
        }
        else {
            return "A" + std::to_string(index);
        }
    }

public:
    std::string solveEquations(int n, const std::vector<std::string>& inputs) {
        std::stringstream result;

        try {
            std::vector<std::vector<Fraction>> coefficients(n, std::vector<Fraction>(n));
            std::vector<Fraction> constants(n);

            int inputIndex = 0;
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    coefficients[i][j] = Fraction(inputs[inputIndex++]);
                }
                constants[i] = Fraction(inputs[inputIndex++]);
            }

            std::vector<Fraction> solution;

            if (n <= 4) {
                result << "Using Cramer's rule to solve...\n\n";
                solution = solveSystemCramer(coefficients, constants);
            }
            else {
                result << "Using Gaussian elimination to solve...\n\n";
                solution = solveSystemGaussian(coefficients, constants);
            }

            result << "The solution to the system is:\n";
            for (int i = 0; i < n; i++) {
                result << getVariableName(i) << " = " << solution[i].toString() << "\n";
            }

            result << "\nDecimal approximations:\n";
            for (int i = 0; i < n; i++) {
                result << getVariableName(i) << " ≈ " << solution[i].toDouble() << "\n";
            }

            result << "\nVerification (substituted into original equations):\n";
            for (int i = 0; i < n; i++) {
                Fraction sum(0);
                for (int j = 0; j < n; j++) {
                    sum = sum + coefficients[i][j] * solution[j];
                }
                result << "Equation " << i + 1 << ": Left = " << sum.toString()
                       << ", Right = " << constants[i].toString()
                       << (sum == constants[i] ? " ✓" : " ✗") << "\n";
            }

        }
        catch (const std::exception& e) {
            result << "Error: " << e.what();
        }

        return result.str();
    }
};

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    bool eventFilter(QObject *obj, QEvent *event) override;

private slots:
    void onVariableCountChanged(int value);
    void onSolveClicked();
    void onClearClicked();
    void onLoadExampleClicked();
    void onInputChanged();

private:
    void setupUI();
    void createInputGrid(int n);
    void loadExampleSystem();
    void updateEquationDisplay();
    void showResult(const QString& result);
    void showError(const QString& error);
    void safeDeleteInputs();
    bool validateInput(const QString& input);

    QWidget *centralWidget;
    QTabWidget *tabWidget;

    QWidget *inputTab;
    QSpinBox *variableSpinBox;
    QScrollArea *inputScrollArea;
    QWidget *inputGridWidget;
    QGridLayout *inputGridLayout;
    QTextEdit *equationDisplay;
    QPushButton *solveButton;
    QPushButton *clearButton;
    QPushButton *exampleButton;
    QProgressBar *progressBar;

    QWidget *resultTab;
    QTextEdit *resultTextEdit;

    std::vector<QLineEdit*> coefficientInputs;
    LinearEquationSolver solver;
    QTimer *solveTimer;
};

#endif // MAINWINDOW_H
